﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using Gumini.JulaDB.Enums;

namespace Gumini.JulaDB.Provider
{
    [System.ComponentModel.DesignerCategory("")]
    public class JulaDbCommand : DbCommand
    {
        private JulaDbConnection _connection;
        private readonly JulaDbParameterCollection _parameters = new JulaDbParameterCollection();

        #region Constructors

        public JulaDbCommand() : this(null, null) { }
        public JulaDbCommand(string commandText) : this(commandText, null) { }
        public JulaDbCommand(JulaDbConnection connection) : this(null, connection) { }
        public JulaDbCommand(string commandText, JulaDbConnection connection)
        {
            this.CommandText = commandText;
            _connection = connection;
            this.IsOptimizerEnabled = true;
        }

        #endregion

        public override int CommandTimeout { get; set; }

        public bool IsOptimizerEnabled { get; set; }

        /// <summary>
        /// Only the CommandType.Text is supported.
        /// </summary>
        public override CommandType CommandType
        {
            get { return CommandType.Text; }
            set
            {
                if (value != CommandType.Text)
                    throw new NotSupportedException("Only the CommandType.Text is supported");
            }
        }

        public override string CommandText { get; set; }
        
        protected override DbConnection DbConnection
        {
            get { return _connection; }
            set { _connection = (JulaDbConnection)value; }
        }

        public JulaDbParameterCollection JulaParameterCollection { get; protected set; }

        protected override DbParameterCollection DbParameterCollection
        {
            get { return _parameters; }
        }

        protected override DbTransaction DbTransaction { get; set; }

        public override bool DesignTimeVisible { get; set; }

        public override UpdateRowSource UpdatedRowSource { get; set; }

        private IList<CommandResult> Execute()
        {
            if (_connection == null)
                throw new JulaDbException(ErrorCode.ConnectionNotSet, "JulaDbCommand.DbConnection is null.");
            if (CommandText == null)
                throw new JulaDbException(ErrorCode.CommandTextNotSet, "JulaDbCommand.CommandText is null.");
            if (_connection.State != ConnectionState.Open)
                throw new JulaDbException(ErrorCode.InvalidConnectionState, "Connection is not opened.");
            
            return _connection.JulaDb.Execute(CommandText,
                throwOnError: true,
                useOptimizer: this.IsOptimizerEnabled);
        }

        protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
        {
            var results = Execute().Select(r => r.RecordSet).ToList();
            return new JulaDbDataReader(results);
        }

        /// <summary>
        /// This will return the number of rows affected by the last statement.
        /// </summary>
        public override int ExecuteNonQuery()
        {
            var results = Execute();            
            return results.Last().NumberOfRowsAffected;
        }

        /// <summary>
        /// This will return the first column of the first row of the last result set, or null if there is no value.
        /// </summary>
        public override object ExecuteScalar()
        {
            var results = Execute();
            var recordSet = results.Last().RecordSet;
            if (recordSet == null)
                return DBNull.Value;
            else
                return recordSet.Rows[0][0] ?? DBNull.Value;
        }

        /// <summary>
        /// JulaDB does not prepare the statements for execution.
        /// </summary>
        public override void Prepare() { }

        public override void Cancel()
        {
            throw new NotSupportedException("Cancelling a command is not supported.");
        }

        /// <summary>
        /// Creates a new instance of a JulaDbParameter object.
        /// </summary>
        /// <returns>
        protected override DbParameter CreateDbParameter()
        {
            return new JulaDbParameter();
        }
    }
}
